package com.jinly.ryder.ssh.command;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.Session;
import com.jinly.ryder.ssh.command.model.FileInfo;
import com.jinly.ryder.ssh.command.model.LogLine;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class GrepCommand {
    private Session sshSession;
    private Pattern pattern = Pattern.compile("\\d{4}\\-\\d{2}\\-\\d{2} \\d{2}\\:\\d{2}\\:\\d{2}\\.\\d{3}");
    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public GrepCommand(Session sshSession) {
        this.sshSession = sshSession;
    }

    public List<LogLine> exec(FileInfo fileInfo, String timeRegex, String keyword, Long num) {
        ChannelExec channelExec = null;
        BufferedReader input = null;
        List<LogLine> list = new ArrayList<>();
        if (keyword == null) keyword = "";
        try {
            channelExec = (ChannelExec) sshSession.openChannel("exec");
            /*
                -E 是一个可扩展的正则表达式(缩写为 ERE)
                -n 在显示符合样式的那一行之前，标示出该行的列数编号
                -H 在显示符合样式的那一行之前，表示该行所属的文件名称
                -i 忽略字符大小写的差别。
                -m NUM 次匹配后停止
             */
            String command = "grep -E -n -H -i -m " + num + " \"" + timeRegex + ".*" + keyword + "\" " + fileInfo.getFileDir() + "/" + fileInfo.getFileName();
            log.info(command);
            channelExec.setCommand(command);
            channelExec.connect();
            input = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));
            String line;
            while ((line = input.readLine()) != null) {
                LogLine logLine = parseLine(line);
                if (logLine != null) {
                    list.add(logLine);
                }
            }
        } catch (Exception e) {
            log.error("grep  err:{}", e.getMessage());
        } finally {
            try {
                if (input != null) input.close();
                if (channelExec != null) channelExec.disconnect();
            } catch (Exception e) {
            }
        }
        return list;
    }

    private LogLine parseLine(String line) {
        String[] splits = line.split(":", 3);
        if (splits.length == 3) {
            LogLine logLine = new LogLine();
            logLine.setFileName(splits[0]);
            logLine.setLineNum(Long.parseLong(splits[1]));
            logLine.setText(splits[2]);
            Matcher m = pattern.matcher(logLine.getText());
            if (m.find() && m.start() == 0) {
                String dateTimeStr = m.group();
                logLine.setTime(LocalDateTime.parse(dateTimeStr, dateTimeFormatter));
            }
            return logLine;
        }
        return null;
    }
}

